    .syntax unified
    .cpu cortex-a9
    .fpu softvfp
    .thumb

    .section .bootinfo, "a"
    .word   0xEA000016                  // b reset_handler
    .asciz  "eGON.BT0"                  // boot head signature
    .word   0x12345678                  // checksum
    .word   20000                       // SPL size
    .word   0x30                        // header size
    .word   0x30303033                  // version
    .word   0x00020000                  // return value
    .word   0x00028000                  // run address
    .word   0x0                         // eGON version
    .word   0x0                         // platform info (low)
    .word   0x00000034                  // platform info (high)

    .section .vector_table,"ax"
    .globl __vector_table
__vector_table:
    LDR     PC, =reset_handler          // Reset
    LDR     PC, =undefined_handler      // Undefined Instruction
    LDR     PC, =svc_handler            // SVC
    LDR     PC, =prefetch_abort         // Prefetch Abort
    LDR     PC, =data_abort             // Data Abort
    .word   0                           // Reserved
    LDR     PC, =irq_handler            // IRQ
    LDR     PC, =fiq_handler            // FIQ

    .size __vector_table, . - __vector_table

    .section .text.startup,"ax"
    .thumb_func
reset_handler:
    cpsid   i                            // Mask interrupts

    // Disable MMU, DCache, ICache, Branch Prediction
    mrc     p15, 0, r0, c1, c0, 0        // Read SCTLR
    bic     r0, r0, #(1 << 12)           // Clear I bit: disable I-cache
    bic     r0, r0, #(1 << 2)            // Clear C bit: disable D-cache
    bic     r0, r0, #0x2                 // Clear A bit: disable strict alignment
    bic     r0, r0, #(1 << 11)           // Clear Z bit: disable branch prediction
    bic     r0, r0, #1                   // Clear M bit: disable MMU
    mcr     p15, 0, r0, c1, c0, 0        // Write back to SCTLR

    // Set CNTFRQ (for Generic Timer)
    ldr     r0, =24000000
    mcr     p15, 0, r0, c14, c0, 0       // CNTFRQ

    // Setup stack for various modes
    // Enter IRQ mode
    cps     #0x12
    ldr     sp, =_istack_top

    // Enter System/User mode
    cps     #0x1F
    ldr     sp, =_cstack_top

    // Enter Supervisor mode
    cps     #0x13
    ldr     sp, =_cstack_top

    bl      SystemInit
    cpsie   i                            // Enable interrupts

    bl      main                         // Call into C code

    b       .

    .thumb_func
undefined_handler:
    b       .

    .thumb_func
svc_handler:
    b       .

    .thumb_func
prefetch_abort:
    b       .

    .thumb_func
data_abort:
    b       .

    .thumb_func
irq_handler:
    push    {lr}
    push    {r0-r3, r12}

    mrs     r0, spsr
    push    {r0}

    mrc     p15, 4, r1, c15, c0, 0       // GIC base address
    add     r1, r1, #0x2000              // GICC base
    ldr     r0, [r1, #0xC]               // Read IAR

    push    {r0, r1}

    cps     #0x13                        // Switch to Supervisor mode

    push    {lr}
    ldr     r2, =SystemIrqHandler
    blx     r2                           // Call SystemIrqHandler(r0=IAR, r1=GICC base)
    pop     {lr}

    cps     #0x12                        // Back to IRQ mode

    pop     {r0, r1}
    str     r0, [r1, #0x10]              // Write to EOIR

    pop     {r0}
    msr     spsr_cxsf, r0

    pop     {r0-r3, r12}
    pop     {lr}
    subs    pc, lr, #4

    .thumb_func
fiq_handler:
    b       .

    .end
